﻿using Data;
using Data.Tables;
using PayrollExpress.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Linq;
using System.Web.Mvc;

namespace PayrollExpress.Helpers
{
    public static class AdministrationHelper
    {
        #region constants

        public const string StyleHidden = "display:none;";
        public const string StyleShownBlock = "display:block;";
        public const string StyleShownInline = "display:in-line;";

        #endregion

        #region Enums

        public enum HolidayType
        {
            [Description("Regular Holiday")]
            [DefaultValue(100d)]
            Regular = 1,
            [Description("Special Non-Working Day")]
            [DefaultValue(30d)]
            Special = 2
        }

        public enum RateType
        {
            [Description("None")]
            None = 0,
            [Description("Hourly")]
            Hourly = 1,
            [Description("Daily")]
            Daily = 2,
            [Description("Weekly")]
            Weekly = 3,
            [Description("Semi-Monthly")]
            SemiMonthly = 4,
            [Description("Monthly")]
            Monthly = 5
        }

        public enum CalendarMonth
        {
            [Description("Select a month")]
            None = 0,
            [Description("January")]
            Jan = 1,
            [Description("February")]
            Feb = 2,
            [Description("March")]
            Mar = 3,
            [Description("April")]
            Apr = 4,
            [Description("May")]
            May = 5,
            [Description("June")]
            Jun = 6,
            [Description("July")]
            Jul = 7,
            [Description("August")]
            Aug = 8,
            [Description("September")]
            Sep = 9,
            [Description("October")]
            Oct = 10,
            [Description("November")]
            Nov = 11,
            [Description("December")]
            Dec = 12,
        }

        public enum CalendarDay
        {
            [Description("Select a date")]
            None = 0,
            [Description("01")]
            One = 1,
            [Description("02")]
            Two = 2,
            [Description("03")]
            Three = 3,
            [Description("04")]
            Four = 4,
            [Description("05")]
            Five = 5,
            [Description("06")]
            Six = 6,
            [Description("07")]
            Seven = 7,
            [Description("08")]
            Eight = 8,
            [Description("09")]
            Nine = 9,
            [Description("10")]
            Ten = 10,
            [Description("11")]
            Eleven = 11,
            [Description("12")]
            Twelve = 12,
            [Description("13")]
            Thirteen = 13,
            [Description("14")]
            Fourteen = 14,
            [Description("15")]
            Fifteen = 15,
            [Description("16")]
            SixTeen = 16,
            [Description("17")]
            Seventeen = 17,
            [Description("18")]
            Eighteen = 18,
            [Description("19")]
            Nineteen = 19,
            [Description("20")]
            Twenty = 20,
            [Description("21")]
            TwentyOne = 21,
            [Description("22")]
            TwentyTwo = 22,
            [Description("23")]
            TwentyThree = 23,
            [Description("23")]
            TwentyFour = 24,
            [Description("24")]
            TwentyFive = 25,
            [Description("26")]
            TwentySix = 26,
            [Description("27")]
            TwentySeven = 27,
            [Description("28")]
            TwentyEight = 28,
            [Description("29")]
            TwentyNine = 29,
            [Description("30")]
            Thirty = 30,
            [Description("31")]
            ThirtyOne = 31
        }

        #endregion

        #region Drop Down Lists

        public static IEnumerable<SelectListItem> EmploymentTypeDropDownList()
        {
            var db = new DatabaseContext();
            var types = db.EmploymentTypes;
            return types.Where(w => w.IsActive == true).Select(s => new SelectListItem { Value = s.ID.ToString(), Text = s.EmploymentTypeName });
        }

        public static IEnumerable<SelectListItem> HolidayTypeDropDownList()
        {
            var types = new List<SelectListItem>();
            types.Add(new SelectListItem() { Value = ((int)HolidayType.Regular).ToString(), Text = HolidayType.Regular.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)HolidayType.Special).ToString(), Text = HolidayType.Special.ToDescription() });

            return types;
        }

        public static IEnumerable<SelectListItem> RateTypeDropDownList()
        {
            var types = new List<SelectListItem>();
            types.Add(new SelectListItem() { Value = ((int)RateType.None).ToString(), Text = RateType.None.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)RateType.Hourly).ToString(), Text = RateType.Hourly.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)RateType.Daily).ToString(), Text = RateType.Daily.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)RateType.Weekly).ToString(), Text = RateType.Weekly.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)RateType.SemiMonthly).ToString(), Text = RateType.SemiMonthly.ToDescription() });
            types.Add(new SelectListItem() { Value = ((int)RateType.Monthly).ToString(), Text = RateType.Monthly.ToDescription() });            

            return types;
        }

        public static IEnumerable<SelectListItem> WorkLocationDropDownList()
        {
            var db = new DatabaseContext();
            var locations = db.WorkLocations;
            return locations.Where(w => w.IsActive == true).Select(s => new SelectListItem { Value = s.ID.ToString(), Text = s.WorkLocationName });
        }

        public static IEnumerable<SelectListItem> CalendarMonthDropDownList()
        {
            var months = new List<SelectListItem>();
            
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.None).ToString(), Text = CalendarMonth.None.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Jan).ToString(), Text = CalendarMonth.Jan.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Feb).ToString(), Text = CalendarMonth.Feb.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Mar).ToString(), Text = CalendarMonth.Mar.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Apr).ToString(), Text = CalendarMonth.Apr.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.May).ToString(), Text = CalendarMonth.May.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Jun).ToString(), Text = CalendarMonth.Jun.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Jul).ToString(), Text = CalendarMonth.Jul.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Aug).ToString(), Text = CalendarMonth.Aug.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Sep).ToString(), Text = CalendarMonth.Sep.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Oct).ToString(), Text = CalendarMonth.Oct.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Nov).ToString(), Text = CalendarMonth.Nov.ToDescription() });
            months.Add(new SelectListItem() { Value = ((int)CalendarMonth.Dec).ToString(), Text = CalendarMonth.Dec.ToDescription() });

            return months;
        }

        public static IEnumerable<int> CalendarLongMonths()
        {
            var months = new List<int>();

            months.Add((int)CalendarMonth.Jan);
            months.Add((int)CalendarMonth.Mar);
            months.Add((int)CalendarMonth.May);
            months.Add((int)CalendarMonth.Jul);
            months.Add((int)CalendarMonth.Aug);
            months.Add((int)CalendarMonth.Oct);
            months.Add((int)CalendarMonth.Dec);

            return months;
        }

        public static IEnumerable<SelectListItem> CalendarDayDropDownList(int month = 1, int? year = null)
        {
            bool isLongMonth = CalendarLongMonths().Contains(month);
            bool isNotFebruary = !month.Equals((int)CalendarMonth.Feb);
            
            bool isLeapYear = true;
            if (year.HasValue)
                isLeapYear = DateTime.IsLeapYear(year.GetValueOrDefault());

            var days = new List<SelectListItem>();

            days.Add(new SelectListItem() { Value = ((int)CalendarDay.None).ToString(), Text = CalendarDay.None.ToDescription() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.One).ToString(), Text = ((int)CalendarDay.One).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Two).ToString(), Text = ((int)CalendarDay.Two).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Three).ToString(), Text =( (int)CalendarDay.Three).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Four).ToString(), Text = ((int)CalendarDay.Four).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Five).ToString(), Text = ((int)CalendarDay.Five).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Six).ToString(), Text = ((int)CalendarDay.Six).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Seven).ToString(), Text = ((int)CalendarDay.Seven).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Eight).ToString(), Text = ((int)CalendarDay.Eight).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Nine).ToString(), Text = ((int)CalendarDay.Nine).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Ten).ToString(), Text = ((int)CalendarDay.Ten).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Eleven).ToString(), Text = ((int)CalendarDay.Eleven).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Twelve).ToString(), Text = ((int)CalendarDay.Twelve).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Thirteen).ToString(), Text = ((int)CalendarDay.Thirteen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Fourteen).ToString(), Text = ((int)CalendarDay.Fourteen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Fifteen).ToString(), Text = ((int)CalendarDay.Fifteen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.SixTeen).ToString(), Text = ((int)CalendarDay.SixTeen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Seventeen).ToString(), Text = ((int)CalendarDay.Seventeen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Eighteen).ToString(), Text = ((int)CalendarDay.Eighteen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Nineteen).ToString(), Text = ((int)CalendarDay.Nineteen).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.Twenty).ToString(), Text = ((int)CalendarDay.Twenty).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyOne).ToString(), Text = ((int)CalendarDay.TwentyOne).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyTwo).ToString(), Text = ((int)CalendarDay.TwentyTwo).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyThree).ToString(), Text = ((int)CalendarDay.TwentyThree).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyFour).ToString(), Text = ((int)CalendarDay.TwentyFour).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyFive).ToString(), Text = ((int)CalendarDay.TwentyFive).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentySix).ToString(), Text = ((int)CalendarDay.TwentySix).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentySeven).ToString(), Text = ((int)CalendarDay.TwentySeven).ToString() });
            days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyEight).ToString(), Text = ((int)CalendarDay.TwentyEight).ToString() });

            if (isNotFebruary)
            {
                days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyNine).ToString(), Text = ((int)CalendarDay.TwentyNine).ToString() });
                days.Add(new SelectListItem() { Value = ((int)CalendarDay.Thirty).ToString(), Text = ((int)CalendarDay.Thirty).ToString() });

                if (isLongMonth)
                    days.Add(new SelectListItem() { Value = ((int)CalendarDay.ThirtyOne).ToString(), Text = ((int)CalendarDay.ThirtyOne).ToString() });
            }
            else
            {
                if (isLeapYear)
                    days.Add(new SelectListItem() { Value = ((int)CalendarDay.TwentyNine).ToString(), Text = ((int)CalendarDay.TwentyNine).ToString() });
            }

            return days;
        }

        #endregion

        #region List Headers

        public enum ListHeaders
        {
            [Description("ID")]
            ID,
            [Description("Is Active")]
            IsActive,

            #region Emplyment Types

            [Description("Employment Type")]
            EmploymentTypeName,

            #endregion

            #region Holiday Types

            [Description("Holiday Type")]
            HolidayTypeName,
            [Description("Rate %")]
            Rate,
            
            #endregion

            #region Recurring Holidays

            [Description("Date")]
            Date,
            [Description("Month")]
            Month,
            [Description("Day")]
            Day,
            [Description("Description")]
            Description,
            
            #endregion

            #region Users

            [Description("User")]
            UserName,
            [Description("Role")]
            Role,

            #endregion

            #region Work Locations

            [Description("Work Location")]
            WorkLocationName,
            [Description("Address")]
            Address,
            [Description("Contact Numbers")]
            ContactNumbers,

            #endregion
        }
        
        #endregion

        #region Users

        public static UserListModel GetUserListModel(DatabaseContext db, string userName, int? workLocationID)
        {
            workLocationID = workLocationID.HasValue ? workLocationID : BaseHelper.GetUserWorkLocationID(db, userName);

            var model = new UserListModel();

            model.WorkLocations = AdministrationHelper.WorkLocationDropDownList();
            model.SelectedWorkLocationID = workLocationID.GetValueOrDefault();
            model.ListItems = GetUserList(db, workLocationID);
            
            return model;
        }

        public static List<UserQuery> GetUserList(DatabaseContext db, int? workLocationID, bool excludeInactive = false)
        {
            var list = new List<UserQuery>();

            var paramWorkLocationID = new SqlParameter("@WorkLocationID", workLocationID);
            var paramExcludeInactive = new SqlParameter("@ExcludeInactive", excludeInactive);

            list = db.Database
                .SqlQuery<UserQuery>("sp_GetUserList @WorkLocationID, @ExcludeInactive", paramWorkLocationID, paramExcludeInactive)
                .ToList();

            return list;
        }

        public static UserAddEditModel GetUserAddEditModel(DatabaseContext db, int? workLocationID, int? userID = null)
        {
            var model = new UserAddEditModel();

            model.Roles = BaseHelper.GetRoleDropDownList();
            model.WorkLocations = AdministrationHelper.WorkLocationDropDownList();

            if (userID == null)
            {
                model.PageAction = BaseHelper.PageAction.Add.ToString();

                model.Type = new User();
                model.Type.UserName = string.Empty;
                model.Type.RoleID = (int)BaseHelper.UserRole.User;
                model.Type.WorkLocationID = workLocationID.GetValueOrDefault();
                model.Type.IsActive = true;

                model.UserAccess = new UserAccessModel();
                model.Password = string.Empty;
            }
            else
            {
                model.PageAction = BaseHelper.PageAction.Edit.ToString();

                model.Type = db.Users.Where(w => w.ID == userID).SingleOrDefault<User>();
                model.UserAccess = BaseHelper.GetUserAccess(db, model.Type.UserName);
                model.Password = BaseHelper.PasswordDisplayText;
            }

            return model;
        }

        public static DatabaseContext AddNewUserAccess(DatabaseContext db, UserAddEditModel model)
        {
            #region Administration

            var userName = model.Type.UserName;

            if (model.UserAccess.HasUsersAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.Users,
                    UserName = userName
                });
            }

            if (model.UserAccess.HasEmploymentTypesAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.EmploymentTypes,
                    UserName = userName
                });
            }

            //if (model.UserAccess.HasHolidayTypesAccess)
            //{
            //    db.UserPageAccesses.Add(new UserPageAccess()
            //    {
            //        PageID = (int)BaseHelper.Page.HolidayTypes,
            //        UserName = userName
            //    });
            //}

            if (model.UserAccess.HasRecurringHolidaysAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.RecurringHolidays,
                    UserName = userName
                });
            }

            if (model.UserAccess.HasWorkLocationsAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.WorkLocations,
                    UserName = userName
                });
            }

            #endregion

            #region Masterfile

            if (model.UserAccess.HasHolidaysAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.Holidays,
                    UserName = userName
                });
            }

            if (model.UserAccess.HasEmployeesAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.Employees,
                    UserName = userName
                });
            }

            if (model.UserAccess.HasEmployeeContractsAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.EmployeeContracts,
                    UserName = userName
                });
            }

            #endregion

            #region Workspace

            if (model.UserAccess.HasPayrollAccess)
            {
                db.UserPageAccesses.Add(new UserPageAccess()
                {
                    PageID = (int)BaseHelper.Page.Payroll,
                    UserName = userName
                });
            }

            #endregion

            #region Reports

            #endregion

            return db;
        }

        public static DatabaseContext RemoveOldUserAccess(DatabaseContext db, UserAddEditModel model)
        {
            var accesses = db.UserPageAccesses.Where(w => w.UserName == model.Type.UserName);

            foreach (var access in accesses)
            {
                db.UserPageAccesses.Remove(access);
            }

            return db;
        }

        #endregion

        #region Employment Types

        public static EmploymentTypeListModel GetEmploymentTypeListModel(DatabaseContext db)
        {
            var model = new EmploymentTypeListModel();
            model.ListItems = GetEmploymentTypeList(db);
            return model;
        }

        public static List<EmploymentTypeQuery> GetEmploymentTypeList(DatabaseContext db, bool excludeInactive = false)
        {
            var list = new List<EmploymentTypeQuery>();

            var paramExcludeInactive = new SqlParameter("@ExcludeInactive", excludeInactive);

            list = db.Database
                .SqlQuery<EmploymentTypeQuery>("sp_GetEmploymentTypeList @ExcludeInactive", paramExcludeInactive)
                .ToList();

            return list;
        }

        public static EmploymentTypeAddEditModel GetEmploymentTypeAddEditModel(DatabaseContext db, int? id = null)
        {
            var model = new EmploymentTypeAddEditModel();

            if (id == null)
            {
                model.PageAction = BaseHelper.PageAction.Add.ToString();

                model.Type = new EmploymentType();
                model.Type.EmploymentTypeName = string.Empty;
                model.Type.IsActive = true;
            }
            else
            {
                model.PageAction = BaseHelper.PageAction.Edit.ToString();
                
                var type = db.EmploymentTypes.Where(w => w.ID == id).SingleOrDefault<EmploymentType>();
                model.Type = type;
            }

            return model;
        }

        #endregion

        #region Recurring Holidays

        public static RecurringHolidayListModel GetRecurringHolidayListModel(DatabaseContext db)
        {
            var model = new RecurringHolidayListModel();
            model.ListItems = GetRecurringHolidayList(db);
            return model;
        }

        public static List<RecurringHolidayQuery> GetRecurringHolidayList(DatabaseContext db, bool excludeInactive = false)
        {
            var list = new List<RecurringHolidayQuery>();

            var paramExcludeInactive = new SqlParameter("@ExcludeInactive", excludeInactive);

            list = db.Database
                .SqlQuery<RecurringHolidayQuery>("sp_GetRecurringHolidayList @ExcludeInactive", paramExcludeInactive)
                .ToList();

            return list;
        }

        public static RecurringHolidayAddEditModel GetRecurringHolidayAddEditModel(DatabaseContext db, int? id = null)
        {
            var model = new RecurringHolidayAddEditModel();

            if (id == null)
            {
                model.PageAction = BaseHelper.PageAction.Add.ToString();

                model.Type = new RecurringHoliday();
                model.Type.Month = (int)CalendarMonth.None;
                model.Type.Day = (int)CalendarDay.None;
                model.Type.Description = string.Empty;
                model.Type.IsActive = true;
            }
            else
            {
                model.PageAction = BaseHelper.PageAction.Edit.ToString();

                var type = db.RecurringHolidays.Where(w => w.ID == id).SingleOrDefault<RecurringHoliday>();
                model.Type = type;
            }

            model.CalendarMonths = CalendarMonthDropDownList();
            model.CalendarDays = CalendarDayDropDownList(model.Type.Month);
            model.HolidayTypes = HolidayTypeDropDownList();
            
            return model;
        }

        #endregion

        #region Work Locations

        public static int GetUserWorkLocationID(DatabaseContext db, string userName)
        {
            var id = 0;
            var list = db.Users.Where(w => w.UserName == userName);

            if (list.Any())
                id = list.SingleOrDefault<User>().WorkLocationID;

            return id;
        }

        public static string GetWorkLocationName(DatabaseContext db, int workLocationID)
        {
            var name = string.Empty;
            var list = db.WorkLocations.Where(w => w.ID == workLocationID);

            if (list.Any())
                name = list.SingleOrDefault<WorkLocation>().WorkLocationName;

            return name;

        }

        public static WorkLocationListModel GetWorkLocationListModel(DatabaseContext db)
        {
            var model = new WorkLocationListModel();
            model.ListItems = GetWorkLocationList(db);
            return model;
        }

        public static List<WorkLocationQuery> GetWorkLocationList(DatabaseContext db, bool excludeInactive = false)
        {
            var list = new List<WorkLocationQuery>();

            var paramExcludeInactive = new SqlParameter("@ExcludeInactive", excludeInactive);

            list = db.Database
                .SqlQuery<WorkLocationQuery>("sp_GetWorkLocationList @ExcludeInactive", paramExcludeInactive)
                .ToList();

            return list;
        }

        public static WorkLocationAddEditModel GetWorkLocationAddEditModel(DatabaseContext db, int? id = null)
        {
            var model = new WorkLocationAddEditModel();

            if (id == null)
            {
                model.PageAction = BaseHelper.PageAction.Add.ToString();

                model.Type = new WorkLocation();
                model.Type.WorkLocationName = string.Empty;
                model.Type.Address = string.Empty;
                model.Type.ContactNumbers = string.Empty;
                model.Type.IsActive = true;
            }
            else
            {
                model.PageAction = BaseHelper.PageAction.Edit.ToString();

                var type = db.WorkLocations.Where(w => w.ID == id).SingleOrDefault<WorkLocation>();
                model.Type = type;
            }
            
            return model;
        }

        #endregion

    }

}